package org.grayrabbit.cms.plugin.parsers;

import java.io.InputStream;
import java.util.Iterator;

import org.apache.commons.lang.StringUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.grayrabbit.cms.plugin.ModuleDescriptor;
import org.grayrabbit.cms.plugin.ModuleDescriptorFactory;
import org.grayrabbit.cms.plugin.Plugin;
import org.grayrabbit.cms.plugin.PluginInformation;
import org.grayrabbit.cms.plugin.PluginParseException;
import org.grayrabbit.cms.plugin.PluginPermission;
import org.grayrabbit.cms.plugin.PluginWebMenuItem;
import org.grayrabbit.cms.plugin.Resources;
import org.grayrabbit.cms.plugin.descriptors.UnloadableModuleDescriptor;
import org.grayrabbit.cms.plugin.descriptors.UnloadableModuleDescriptorFactory;
import org.grayrabbit.cms.plugin.descriptors.UnrecognisedModuleDescriptor;
import org.grayrabbit.cms.plugin.descriptors.UnrecognisedModuleDescriptorFactory;
import org.grayrabbit.cms.utils.ClassLoaderUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class XmlDescriptorParser implements DescriptorParser {
	 private static Logger log = LoggerFactory.getLogger(XmlDescriptorParser.class);
	private Document document;
	public XmlDescriptorParser(InputStream source) throws PluginParseException {
		if( source == null){
			throw new IllegalArgumentException("文件源source不能为空!");
		}
		this.document = createDocument(source);
	}

	private Document createDocument(InputStream source) throws PluginParseException {
		SAXReader reader = new SAXReader();
		try{
			return reader.read(source);
		}catch (DocumentException e) {
			throw new PluginParseException("Cannot parse XML plugin descriptor", e);
		}
	}

	public Plugin configurePlugin(ModuleDescriptorFactory moduleDescriptorFactory,Plugin plugin) throws PluginParseException {
		 Element pluginElement = getPluginElement();
		 plugin.setName(pluginElement.attributeValue("name"));
		 plugin.setKey(getKey());
		 if (pluginElement.attributeValue("i18n-name-key") != null)
		    {
		      plugin.setI18nNameKey(pluginElement.attributeValue("i18n-name-key"));
		    }

		    if (plugin.getKey().indexOf(":") > 0) {
		      throw new PluginParseException("Plugin keys cannot contain ':'. Key is '" + plugin.getKey() + "'");
		    }
		    for (@SuppressWarnings("rawtypes")
			Iterator i = pluginElement.elementIterator(); i.hasNext(); )
		    {
		      Element element = (Element)i.next();
		      if ("plugin-info".equalsIgnoreCase(element.getName()))
		      {
		        plugin.setPluginInformation(createPluginInformation(element));
		      }else if("init".equalsIgnoreCase(element.getName())){
		    	  createInitInformation(plugin,element);
		     }else if("web-item".equalsIgnoreCase(element.getName())){
		    	 plugin.addWebMenuItem(createWebItem(element));
		     }else if("portlet".equalsIgnoreCase(element.getName())){
		    	  //TODO 暂时不处理portlent，后期扩展只需删除当前else if 
		    }else if (!"resource".equalsIgnoreCase(element.getName())){
		        ModuleDescriptor moduleDescriptor = createModuleDescriptor(plugin, element, moduleDescriptorFactory);
		        if (moduleDescriptor == null) {
		          continue;
		        }
//		        if (plugin.getModuleDescriptor(moduleDescriptor.getKey()) != null) {
//		          throw new PluginParseException("Found duplicate key '" + moduleDescriptor.getKey() + "' within plugin '" + plugin.getKey() + "'");
//		        }
//		        plugin.addModuleDescriptor(moduleDescriptor);
//
//		        if ((moduleDescriptor instanceof UnloadableModuleDescriptor))
//		        {
//		          log.error("There were errors loading the plugin '" + plugin.getName() + "'. The plugin has been disabled.");
//		          return UnloadablePluginFactory.createUnloadablePlugin(plugin);
//		        }
		      }
		    }

		    plugin.setResources(Resources.fromXml(pluginElement));
		    return plugin;
	}

	private PluginWebMenuItem createWebItem(Element element) {
		PluginWebMenuItem item = new PluginWebMenuItem();
		item.setMenuItemId(element.attributeValue("key"));
		item.setType(element.attributeValue("type"));
		if(element.element("label") != null){
			item.setLabelKey(element.element("label").attributeValue("key"));
		}
		if(element.element("link") != null){
			String linkId = element.element("link").attributeValue("linkId");
			if(StringUtils.isNotEmpty(linkId)){
				item.setLinkId(linkId.trim());
			}
			if(element.element("link").getText()!=null){
				item.setUrl(element.element("link").getTextTrim());
			}
		}
		return item;
	}

	private void createInitInformation(Plugin plugin,Element element) {
		if (element.element("install") != null) {
			String installerStr = element.element("install").attributeValue("class");
			if(StringUtils.isNotEmpty(installerStr)){
				try {
					plugin.setInstaller(ClassLoaderUtils.loadClass(installerStr, getClass()));
				} catch (ClassNotFoundException e) {
					throw new IllegalArgumentException("不能加在插件‘"+plugin.getName()+"'的初化始安装类'"+installerStr+"'",e);
				}
			}
		}else if(element.element("permissions") != null){
			Element pEl = element.element("permissions");
			if(pEl.elements("property")!=null){
				for(Iterator<?> i = pEl.elements("property").iterator() ;i.hasNext() ;){
					Element pe  = (Element) i.next();
					PluginPermission p3 =createPermissionProperty(pe);
					plugin.addPluginPermission(p3);
				}
			}
		}else if(element.element("permissions") != null){
		}
	}

	private PluginPermission createPermissionProperty(Element element){
		PluginPermission p3 = new PluginPermission();
		if(element.attributeValue("key")!=null){
			p3.setKey(element.attributeValue("key").trim());
		}
		if(element.attributeValue("value")!=null){
			p3.setValue(element.attributeValue("value").trim());
		}
		if(element.attributeValue("desc")!=null){
			p3.setDesc(element.attributeValue("desc").trim());
		}
		return p3;
	}
	private ModuleDescriptor createModuleDescriptor(Plugin plugin,Element element, ModuleDescriptorFactory moduleDescriptorFactory) throws PluginParseException {
		String name = element.getName();
	    ModuleDescriptor moduleDescriptorDescriptor;
	    try
	    {
	      moduleDescriptorDescriptor = moduleDescriptorFactory.getModuleDescriptor(name);
	    }
	    catch (Throwable e)
	    {
			UnrecognisedModuleDescriptor descriptor = UnrecognisedModuleDescriptorFactory.createUnrecognisedModuleDescriptor(plugin, element, e,
							moduleDescriptorFactory);
			log.error("加载插件'{}'中的模块 '{}'存在一些问题, 该模块禁用.", plugin.getName(), name);
			log.error(descriptor.getErrorText(), e);
			return descriptor;
	    }
	    if (moduleDescriptorDescriptor == null)
	    {
	      log.info("The module '" + name + "' in plugin '" + plugin.getName() + "' is in the list of excluded module descriptors, so not enabling.");
	      return null;
	    }

	    try
	    {
	      moduleDescriptorDescriptor.init(plugin, element);
	    }
	    catch (PluginParseException e)
	    {
	      UnloadableModuleDescriptor descriptor = UnloadableModuleDescriptorFactory.createUnloadableModuleDescriptor(plugin, element, e, moduleDescriptorFactory);
	      log.error("There were problems loading the module '" + name + "'. The module and its plugin have been disabled.");
	      log.error(descriptor.getErrorText(), e);
	      return descriptor;
	    }
	    return moduleDescriptorDescriptor;
	}

	private PluginInformation createPluginInformation(Element element) {
		PluginInformation pluginInfo = new PluginInformation();
		if (element.element("description") != null) {
			pluginInfo.setDescription(element.element("description").getTextTrim());
			if (element.element("description").attributeValue("key") != null) {
				pluginInfo.setDescriptionKey(element.element("description").attributeValue("key"));
			}
		}

		if (element.element("version") != null) {
			pluginInfo.setVersion(element.element("version").getTextTrim());
		}
		if (element.element("vendor") != null) {
			Element vendor = element.element("vendor");
			pluginInfo.setVendorName(vendor.attributeValue("name"));
			pluginInfo.setVendorUrl(vendor.attributeValue("url"));
		}

		if (element.element("application-version") != null) {
			pluginInfo.setMaxVersion(Float.parseFloat(element.element("application-version").attributeValue("max")));
			pluginInfo.setMinVersion(Float.parseFloat(element.element("application-version").attributeValue("min")));
		}

		if (element.element("java-version") != null) {
			pluginInfo.setMinJavaVersion(Float.valueOf(element.element("java-version").attributeValue("min")));
		}

		return pluginInfo;
	}

	public String getKey() {
		 return getPluginElement().attributeValue("key");
	}

	private Element getPluginElement() {
		return this.document.getRootElement();
	}

	public boolean isSystemPlugin() {
		return false;
	}

}
